Skip to content

Fix #80, support an include mechanism for PDI config#653

Draft
JAuriac wants to merge 1 commit intopdidev:mainfrom
JAuriac:80-support-an-include-mechanism-for-pdi-config
Draft

Fix #80, support an include mechanism for PDI config#653
JAuriac wants to merge 1 commit intopdidev:mainfrom
JAuriac:80-support-an-include-mechanism-for-pdi-config

Conversation

@JAuriac
Copy link
Copy Markdown
Contributor

@JAuriac JAuriac commented Mar 18, 2026

Support an include mechanism for PDI config, to include other YAML files into root YAML document.
Depends on Paraconf handling of relative path to point to included YAML files.

List of things to check before making a PR

Before merging your code, please check the following:

  • you have added a line describing your changes to the Changelog;
  • you have added unit tests for any new or improved feature;
  • in case you updated dependencies, you have checked pdi/docs/CheckList.md;
  • in case of a change in pdi.h, this same change must be reflected in no-pdi/include/pdi.h;
  • you have checked your code format:
    • you have checked that you respect all conventions specified in CONTRIBUTING.md;
    • you have checked that the indentation and formatting conforms to the .clang-format;
    • you have documented with doxygen any new or changed function / class;
  • you have correctly updated the copyright headers:
    • your institution is in the copyright header of every file you (substantially) modified;
    • you have checked that the end-year of the copyright there is the current one;
  • you have updated the AUTHORS file:
    • you have added yourself to the AUTHORS file;
    • if this is a new contribution, you have added it to the AUTHORS file;
  • you have added everything to the user documentation:
    • any new CMake configuration option;
    • any change in the yaml config;
    • any change to the public or plugin API;
    • any other new or changed user-facing feature;
    • any change to the dependencies;
  • you have correctly linked your MR to one or more issues:
    • your MR solves an identified issue;
    • your commit contain the Fix #issue keyword to autoclose the issue when merged.

@JAuriac JAuriac linked an issue Mar 18, 2026 that may be closed by this pull request
Comment thread pdi/src/global_context.cxx Outdated
Comment thread tests/test_07.yml Outdated
Comment thread tests/test_07_data.yml Outdated
Comment thread tests/test_07.yml Outdated
Comment thread pdi/src/global_context.cxx Outdated
Comment thread tests/test_07_data.yml Outdated
Comment thread pdi/src/global_context.cxx Outdated
Comment on lines +110 to +113
PC_tree_t pdi = PC_get(conf, ".pdi");
if (!PC_status(pdi)) {
root = pdi;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't do that ! It's up to the user to do that if they want.

Maybe the syntax could support 2 variants:
either:

include:
- /path/to/my/file.yaml

or

include:
- file: /path/to/my/file.yaml
  node: .pdi[5]

where node is any valid ypath (paraconf) expression

@JAuriac
Copy link
Copy Markdown
Contributor Author

JAuriac commented Mar 19, 2026

As we currently need the full path to read a yaml subfile, the test_07 works on the github runner for linux (through a workaround overwriting a placeholder field in the root yaml file) but not for macos, and not for local

@JAuriac
Copy link
Copy Markdown
Contributor Author

JAuriac commented Mar 28, 2026

The integrations tests "test_duplicate_yaml_include" and "test_circular_yaml_include" are disabled by default, as they expect failure. We use instead the unitary tests "check_duplicate" and "load_pdi_config_duplicate_data_via_inclusion", using System_error.
This last commit only test using absolute paths for the CI, with Paraconf 1.0.3 (also tested locally for both absolute and relative paths, with Paraconf 1.1.1).

Comment thread spack.yaml Outdated
Comment thread CMakeLists.txt Outdated
Comment thread CMakeLists.txt Outdated
Comment thread CHANGELOG.md Outdated
Comment thread pdi/src/global_context.cxx Outdated
Comment on lines +67 to +76
#ifdef PARACONF_VERSION_MAJOR
#if (PARACONF_VERSION_MAJOR > 1) || (PARACONF_VERSION_MAJOR == 1 && PARACONF_VERSION_MINOR >= 1)
#define PDI_HAS_PC_PATH 1
#else
#define PDI_HAS_PC_PATH 0
#endif
#else
#define PDI_HAS_PC_PATH 0
#endif

Copy link
Copy Markdown
Member

@Yushan-Wang Yushan-Wang Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really necessary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, to use absolute paths with Paraconf < 1.1, and both absolute and relative paths with Paraconf 1.1+

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend this pattern:

Suggested change
#ifdef PARACONF_VERSION_MAJOR
#if (PARACONF_VERSION_MAJOR > 1) || (PARACONF_VERSION_MAJOR == 1 && PARACONF_VERSION_MINOR >= 1)
#define PDI_HAS_PC_PATH 1
#else
#define PDI_HAS_PC_PATH 0
#endif
#else
#define PDI_HAS_PC_PATH 0
#endif
#if defined(PARACONF_VERSION) && (PARACONF_UNTYPED_VERSION >= PARACONF_UNTYPED_COMPUTE_VERSION(1, 1, 0))
#define PDI_HAS_PC_PATH 1
#else
#define PDI_HAS_PC_PATH 0
#endif

of you could directly do the test where needed

namespace {

void load_data(Context& ctx, PC_tree_t node, bool is_metadata)
void load_data(Global_context& ctx, PC_tree_t node, bool is_metadata)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why changing to global_context?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed back

Copy link
Copy Markdown
Contributor Author

@JAuriac JAuriac Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed again, to use make_and_check_descriptor() which is accessible only from Global_context (and not Context)

Comment thread pdi/src/global_context.cxx Outdated
Comment on lines +137 to +138
std::unordered_set<std::string> visited;
collect_plugins_impl(conf, visited);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this is required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was used to handle the dual pass. We are now back to a single pass on the PC tree, with two sub-pass to read plugins, then types/metadata/data.

@JAuriac JAuriac requested review from Yushan-Wang and jbigot April 3, 2026 13:16
@JAuriac JAuriac marked this pull request as draft April 7, 2026 14:24
Comment thread pdi/src/global_context.cxx Outdated
Comment on lines +67 to +76
#ifdef PARACONF_VERSION_MAJOR
#if (PARACONF_VERSION_MAJOR > 1) || (PARACONF_VERSION_MAJOR == 1 && PARACONF_VERSION_MINOR >= 1)
#define PDI_HAS_PC_PATH 1
#else
#define PDI_HAS_PC_PATH 0
#endif
#else
#define PDI_HAS_PC_PATH 0
#endif

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend this pattern:

Suggested change
#ifdef PARACONF_VERSION_MAJOR
#if (PARACONF_VERSION_MAJOR > 1) || (PARACONF_VERSION_MAJOR == 1 && PARACONF_VERSION_MINOR >= 1)
#define PDI_HAS_PC_PATH 1
#else
#define PDI_HAS_PC_PATH 0
#endif
#else
#define PDI_HAS_PC_PATH 0
#endif
#if defined(PARACONF_VERSION) && (PARACONF_UNTYPED_VERSION >= PARACONF_UNTYPED_COMPUTE_VERSION(1, 1, 0))
#define PDI_HAS_PC_PATH 1
#else
#define PDI_HAS_PC_PATH 0
#endif

of you could directly do the test where needed


Global_context::Global_context(PC_tree_t conf)
: m_logger{"PDI", PC_get(conf, ".logging")}
, m_plugins{*this, conf}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will load the plugins at the construction of the object and should be reworked

Comment thread pdi/include/pdi/context.h Outdated
Comment thread pdi/src/global_context.cxx Outdated
Comment thread pdi/src/global_context.cxx
Comment thread pdi/src/global_context.cxx Outdated
load_pdi_config(conf); // single tree traversal + two flat sub-passes

// evaluate pattern after loading plugins
m_logger.evaluate_pattern(*this);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be par of load_pdi_config?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept this separated as it previously was, to not make a unique monolithic function inside of the Global_context definition

Comment thread pdi/src/global_context.cxx Outdated
Comment on lines +226 to +249
void Global_context::check_duplicate(const PC_tree_t& node, const std::string& name)
{
auto [it, inserted] = m_defined.emplace(name, node);
if (!inserted) {
// it->second = first definition site (deepest file in include tree, post-order)
// node = redefinition site (current file being processed)
#if PDI_HAS_PC_PATH
const char* orig_path = PC_path(it->second);
const char* redef_path = PC_path(node);

bool orig_has_path = orig_path && fs::exists(orig_path);
bool redef_has_path = redef_path && fs::exists(redef_path);

if (redef_has_path && orig_has_path) {
throw Config_error(node, "Duplicate definition of '{}', originally defined in '{}', defined again in '{}'", name, redef_path, orig_path);
} else if (redef_has_path) {
throw Config_error(node, "Duplicate definition of '{}', originally defined in string config, defined again in '{}'", name, redef_path);
} else if (orig_has_path) {
throw Config_error(node, "Duplicate definition of '{}', originally defined in '{}', defined again in a string config", name, orig_path);
}
#endif
throw Config_error(node, "Duplicate definition of '{}'", name);
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think you need a dedicated function

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get the 'Config_error' with the lines numbers without a new function ?

Comment thread pdi/src/global_context.h Outdated
Comment on lines +82 to +91
void collect_ordered_nodes_impl(
PC_tree_t conf,
std::unordered_set<std::string>& globally_loaded,
std::unordered_set<std::string>& include_chain,
std::vector<std::pair<std::string, PC_tree_t>>& ordered_nodes,
std::size_t& no_path_counter,
const std::string& known_path = "",
PC_tree_t include_directive = {},
const std::string& parent_id = ""
);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cound't this be a static function in the cxx?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'collect_ordered_nodes_impl', yes, but not 'collect_ordered_nodes', as we need a public member, used by 'load_pdi_config' ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved both collect_ordered_nodes() and collect_ordered_nodes() to the local namespace instead

Comment thread pdi/src/global_context.h Outdated
Comment on lines +147 to +158
/// Traverses the include tree once in post-order (deepest includes first),
/// filling `ordered_nodes` with (canonical_id, PC_tree_t) pairs.
/// Diamond/circular detection is handled here.
void collect_ordered_nodes(
PC_tree_t conf,
std::unordered_set<std::string>& globally_loaded,
std::unordered_set<std::string>& include_chain,
std::vector<std::pair<std::string, PC_tree_t>>& ordered_nodes,
const std::string& known_path = "",
PC_tree_t include_directive = {},
const std::string& parent_id = ""
);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cound't this be a static function in the cxx?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'collect_ordered_nodes_impl', yes, but not 'collect_ordered_nodes', as we need a public member, used by 'load_pdi_config' ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved both collect_ordered_nodes() and collect_ordered_nodes() to the local namespace instead

@JAuriac JAuriac force-pushed the 80-support-an-include-mechanism-for-pdi-config branch 4 times, most recently from 97ff407 to a9e7c87 Compare April 22, 2026 07:46
@jbigot jbigot force-pushed the main branch 6 times, most recently from 41fed24 to b9ebda1 Compare April 24, 2026 09:13
@JAuriac JAuriac marked this pull request as ready for review April 29, 2026 08:32
@JAuriac JAuriac requested a review from jbigot April 29, 2026 08:32
@jbigot jbigot marked this pull request as draft May 5, 2026 13:54
@jbigot jbigot assigned jbigot and unassigned jbigot and JAuriac May 5, 2026
Co-authored-by: Julian Auriac <julian.auriac@cea.fr>
@jbigot jbigot force-pushed the 80-support-an-include-mechanism-for-pdi-config branch from 2078b40 to 118b45a Compare May 7, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support an include mechanism for PDI config

3 participants